package pri.zxx.nio;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

/**
 * @author Twilight
 * @desc 通道测试
 * @createTime 2019-06-29-23:09
 */
@Slf4j
public class ChannelTest {

    /*----------------------  通道操作 -----------------------*/
    //FileChanel SocketChannel ServerSocketChannel dataGramChannel
    //支持通道的类提供了getChannel()
    //本地io fileInp FileOutP RandomAccessFile
    // jdk 1.7后 静态方法 open （）
    // Files工具类 newByteChannel()

    @SneakyThrows
    @Test
    public void channelTest() {
        FileInputStream fileInputStream = new FileInputStream("logs/log.log");
        FileChannel open = FileChannel.open(Paths.get("myfiles/io.txt"), StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE);

        FileChannel in = fileInputStream.getChannel();
        ByteBuffer bf = ByteBuffer.allocate(1024);
        while (in.read(bf) != -1) {
            bf.flip();
            open.write(bf);
            bf.clear();
        }
        open.close();
        in.close();
        fileInputStream.close();
    }


    /**
     * 直接内存复制文件
     */
    @Test
    public void directMemory() throws IOException {
        //物理内存缓存 （内存映射文件）
//        String from = "logs/log.log";
        String from = "/Users/xigua/codes/zxxcodes/learn_demo/src/main/resources/files/favicon.ico";
        String to = "/Users/xigua/codes/zxxcodes/learn_demo/src/main/resources/files/copy.jpg";
        FileChannel inOpen = FileChannel.open(Paths.get(from), StandardOpenOption.READ);
        FileChannel outOpen = FileChannel.open(Paths.get(to), StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE);

        //内存映射文件
        MappedByteBuffer inMap = inOpen.map(FileChannel.MapMode.READ_ONLY, 0, inOpen.size());
        MappedByteBuffer outMap = outOpen.map(FileChannel.MapMode.READ_WRITE, 0, inOpen.size());

        //直接对缓存区进行数据操作
        byte[] bytes = new byte[inMap.limit()];
        inMap.get(bytes);
        outMap.put(bytes);
        inOpen.close();
        outOpen.close();

    }

    /**
     * 通道之间的数据传输
     * <p>
     * transferFrom()
     * transferTo()
     */
    @SneakyThrows
    @Test
    public void channelTransfer() {
        String dir = "logs";
        String from = "log.log";
        String to = "to" + from;


        FileChannel inOpen = FileChannel.open(Paths.get(dir, from), StandardOpenOption.READ);
        FileChannel outOpen = FileChannel.open(Paths.get(dir, to), StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE);
        inOpen.transferTo(0, inOpen.size(), outOpen);
        inOpen.close();
        outOpen.close();

    }

    /**
     * Scatter 分散  聚集Gather
     * 分散读取（多个通道读取），聚集写入（多个通道写入单个）
     */
    @SneakyThrows
    @Test
    public void scatterGather() {
        String dir = "logs";
        String from = "log.log";
        String to = "to2" + from;

        RandomAccessFile randomAccessFile = new RandomAccessFile(dir + "/" + from, "rw");
        FileChannel channel = randomAccessFile.getChannel();
        ByteBuffer allocate = ByteBuffer.allocate(1024);
        ByteBuffer allocate2 = ByteBuffer.allocate(102400);

        ByteBuffer[] bufs = {allocate, allocate2};
        channel.read(bufs);
        for (ByteBuffer buf : bufs) {
            buf.flip();
            log.warn(new String(buf.array()));
            log.warn("----------------------------");
        }

        RandomAccessFile randomAccessFile1 = new RandomAccessFile(dir + "/" + to, "rw");
        FileChannel out = randomAccessFile1.getChannel();
        for (ByteBuffer buf : bufs) {
            out.write(buf, out.size());
        }
        channel.close();
        out.close();

    }
}
